<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
	<head>
		<script type="text/javascript" src="_config.js"></script>
		<script type="text/javascript" src="../js/jquery-1.6.2.min.js"></script>
	   	<script type="text/javascript" src="../js/crypto-sha1-hmac-pbkdf2-blockmodes-aes.js"></script>
	   	<script type="text/javascript" src="../js/crypto-sha256.js"></script>
	   	<script type="text/javascript" src="../js/json2.js"></script>
		<script type="text/javascript" src="qunit.js"></script>
		<link rel="stylesheet" type="text/css" href="qunit.css" />
    	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
		<title>Kee Book Test Page: RESTful Web Services</title>
		<script type="text/javascript">
			/* <![CDATA[ */
				$(document).ready(function() {
					api_auth();
					crud_kee_book();
					crud_password_item();
					crud_group();
					
					/***********************************************/
					/*    BASIC API CONNECTION AND AUTHENTICATION  */
					/***********************************************/
					function api_auth() {		
						asyncTest("Basic API connection and authentication with correct credentials", function() {
							$.ajax({
								'type': 'GET',
								'async': false,
								'data': {'password': config.password},
								'dataType': 'json',
								'url': config.servicesUrl + '/' + config.username + '/getkeebook',
								'success': function(data) {
									ok(data, "returned data is an object");
									ok(data.authSuccess, "authentication was successful");
									ok(data.success, "overall result was successful");
									start();
								},
								'error': function() {
									ok(false, "service call returned with error");
									start();
								}
							});
						});
	
						asyncTest("Basic API connection and authentication without password", function() {
							$.ajax({
								'type': 'GET',
								'async': false,
								'dataType': 'json',
								'url': config.servicesUrl + '/' + config.username + '/getkeebook',
								'success': function(data) {
									ok(data, "returned data is an object");
									ok(!data.authSuccess, "authentication was not successful");
									ok(!data.success, "overall result was not successful");
									start();
								},
								'error': function() {
									ok(false, "service call returned with error");
									start();
								}
							});
						});
	
						asyncTest("Basic API connection and authentication without username", function() {
							$.ajax({
								'type': 'GET',
								'async': false,
								'data': {'password': config.password},
								'dataType': 'json',
								'url': config.servicesUrl + '/getkeebook',
								'success': function(data) {
									ok(false, "got http success, but should fail with 500");
									start();
								},
								'error': function() {
									ok(true, "got 500 bad request as expected");
									start();
								}
							});
						});
	
						asyncTest("Basic API connection and authentication with incorrect username", function() {
							$.ajax({
								'type': 'GET',
								'async': false,
								'data': {'password': config.password},
								'dataType': 'json',
								'url': config.servicesUrl + '/' + (config.username + 'qwertz') + '/getkeebook',
								'success': function(data) {
									ok(data, "returned data is an object");
									ok(!data.authSuccess, "authentication was not successful");
									ok(!data.success, "overall result was not successful");
									start();
								},
								'error': function() {
									ok(false, "service call returned with error");
									start();
								}
							});
						});
	
						asyncTest("Basic API connection and authentication with incorrect password", function() {
							$.ajax({
								'type': 'GET',
								'async': false,
								'data': {'password': (config.password + 'qwertz')},
								'dataType': 'json',
								'url': config.servicesUrl + '/' + config.username + '/getkeebook',
								'success': function(data) {
									ok(data, "returned data is an object");
									ok(!data.authSuccess, "authentication was not successful");
									ok(!data.success, "overall result was not successful");
									start();
								},
								'error': function() {
									ok(false, "service call returned with error");
									start();
								}
							});
						});
					}

					/***********************************************/
					/*        CRUD KEE BOOK                        */
					/***********************************************/
					function crud_kee_book() {
						var salt = "";
						var keeBookId = "";
						var keeBookChecksum = "";
						var randomTitle = "Test Kee Book " + Math.abs(Math.random()*1000000);
						var randomTitle2 = "Test Kee Book " + Math.abs(Math.random()*1000000);
						var randomPassword = Math.abs(Math.random()*1000000);
						crud_book_f10();

						function crud_book_f10() {
							asyncTest("CRUD Kee Book: Request Salt", function() {
		
								$.ajax({
									'type': 'GET',
									'data': {'password': (config.password)},
									'dataType': 'json',
									'url': config.servicesUrl + '/' + config.username + '/getsalt',
									'success': function(data) {
										ok(data, "returned data is an object");
										ok(data.authSuccess, "authentication was successful");
										ok(data.success, "overall result was successful");
										ok(data.salt, "salt is included in result");
										salt = data.salt;
										keeBookChecksum = Crypto.SHA256(Crypto.SHA256(randomPassword) + salt);

										start();
										crud_book_f20();
									},
									'error': function() {
										ok(false, "service call returned with error");
										start();
									}
								});
							});
						}

						function crud_book_f20() {
							asyncTest("CRUD Kee Book: Create Kee Book", function() {
								$.ajax({
									'type': 'POST',
									'data': JSON.stringify({
										'password': config.password,
										'data': {
											'title': randomTitle,
											'salt': salt,
											'keeBookChecksum': keeBookChecksum
										}
									}),
									'dataType': 'json',
									'contentType': 'application/json',
									'url': config.servicesUrl + '/' + config.username + '/createkeebook',
									'success': function(data) {
										ok(data, "returned data is an object");
										ok(data.authSuccess, "authentication was successful");
										ok(data.success, "overall result was successful");
										ok(data.keeBookId, "keeBookId is included in result");
										keeBookId = data.keeBookId;

										start();
										crud_book_f30();
									},
									'error': function() {
										ok(false, "service call returned with error");
										start();
									}
								});
							});
						}

						function crud_book_f30() {
							asyncTest("CRUD Kee Book: Get list of kee books", function() {
								$.ajax({
									'type': 'GET',
									'data': {'password': (config.password)},
									'dataType': 'json',
									'url': config.servicesUrl + '/' + config.username + '/getkeebook',
									'success': function(data) {
										ok(data, "returned data is an object");
										ok(data.authSuccess, "authentication was successful");
										ok(data.success, "overall result was successful");
										ok(data.count, "number of records is included in result");
										ok((data.count > 0), "number of records is > 0");
										ok(data.result, "result object is included in result");
										var included = false;
										for (var i=0; i<data.count; i++) {
											if (data.result[i].id == keeBookId && data.result[i].title == randomTitle) {
												included = true;
											}
										}
										ok(included, "created kee book is included in result list");

										start();
										crud_book_f40();
									},
									'error': function() {
										ok(false, "service call returned with error");
										start();
									}
								});
							});
						}

						function crud_book_f40() {
							asyncTest("CRUD Kee Book: Update kee book", function() {
								$.ajax({
									'type': 'POST',
									'data': JSON.stringify({
										'password': config.password,
										'keeBook': keeBookId,
										'keeBookChecksum': keeBookChecksum,
										'data': {
											'title': randomTitle2
										}
									}),
									'dataType': 'json',
									'contentType': 'application/json',
									'url': config.servicesUrl + '/' + config.username + '/updatekeebook',
									'success': function(data) {
										ok(data, "returned data is an object");
										ok(data.authSuccess, "authentication was successful");
										ok(data.success, "overall result was successful");
										ok(data.keeBookId, "keeBookId is included in result");
										ok(data.keeBookId == keeBookId, "keeBookId matches newly created one");

										start();
										crud_book_f50();
									},
									'error': function() {
										ok(false, "service call returned with error");
										start();
									}
								});
							});
						}

						function crud_book_f50() {
							asyncTest("CRUD Kee Book: Try to update Kee Book with wrong passphrase", function() {
								$.ajax({
									'type': 'POST',
									'data': JSON.stringify({
										'password': config.password,
										'keeBook': keeBookId,
										'keeBookChecksum': (keeBookChecksum + 'qwertz'),
										'data': {
											'title': randomTitle
										}
									}),
									'dataType': 'json',
									'contentType': 'application/json',
									'url': config.servicesUrl + '/' + config.username + '/updatekeebook',
									'success': function(data) {
										ok(data, "returned data is an object");
										ok(!data.authSuccess, "authentication was not successful");
										ok(!data.success, "overall result was not successful");

										start();
										crud_book_f60();
									},
									'error': function() {
										ok(false, "service call returned with error");
										start();
									}
								});
							});
						}

						function crud_book_f60() {
							asyncTest("CRUD Kee Book: Delete kee book", function() {
								$.ajax({
									'type': 'GET',
									'data': {
										'password': (config.password),
										'keeBook': keeBookId,
										'keeBookChecksum': keeBookChecksum
									},
									'dataType': 'json',
									'url': config.servicesUrl + '/' + config.username + '/deletekeebook',
									'success': function(data) {
										ok(data, "returned data is an object");
										ok(data.authSuccess, "authentication was successful");
										ok(data.success, "overall result was successful");

										start();
										crud_book_f70();
									},
									'error': function() {
										ok(false, "service call returned with error");
										start();
									}
								});
							});
						}

						function crud_book_f70() {
							asyncTest("CRUD Kee Book: Get list of kee books", function() {
								$.ajax({
									'type': 'GET',
									'data': {'password': (config.password)},
									'dataType': 'json',
									'url': config.servicesUrl + '/' + config.username + '/getkeebook',
									'success': function(data) {
										ok(data, "returned data is an object");
										ok(data.authSuccess, "authentication was successful");
										ok(data.success, "overall result was successful");
										ok(data.result, "result object is included in result");
										var included = false;
										for (var i=0; i<data.count; i++) {
											if (data.result[i].id == keeBookId && data.result[i].title == randomTitle) {
												included = true;
											}
										}
										ok(!included, "created kee book is not included in result list anymore");
										start();
									},
									'error': function() {
										ok(false, "service call returned with error");
										start();
									}
								});
							});
						}
					}

					/***********************************************/
					/*        CRUD PASSWORD ITEM                   */
					/***********************************************/
					function crud_password_item() {
						var salt = "";
						var keeBookId = "";
						var keeBookChecksum = "";
						var randomTitle = "Test Kee Book " + Math.abs(Math.random()*1000000);
						var randomItemTitleA = "Test Item " + Math.abs(Math.random()*1000000);
						var randomItemTitleB = "Test Item " + Math.abs(Math.random()*1000000);
						var randomPassword = Math.abs(Math.random()*1000000) + "";
						var itemIdA = "";
						var itemIdB = "";

						crud_item_f10();

						function crud_item_f10() {
							asyncTest("CRUD Item: Request salt", function() {
								$.ajax({
									'type': 'GET',
									'data': {'password': (config.password)},
									'dataType': 'json',
									'url': config.servicesUrl + '/' + config.username + '/getsalt',
									'success': function(data) {
										ok(data, "returned data is an object");
										ok(data.authSuccess, "authentication was successful");
										ok(data.success, "overall result was successful");
										ok(data.salt, "salt is included in result");
										salt = data.salt;
										keeBookChecksum = Crypto.SHA256(Crypto.SHA256(randomPassword) + salt);
										
										start();
										crud_item_f20();
									},
									'error': function() {
										ok(false, "service call returned with error");
										start();
									}
								});
							});
						}
						
						function crud_item_f20() {
							asyncTest("CRUD Item: Create blank kee book", function() {
								$.ajax({
									'type': 'POST',
									'data': JSON.stringify({
										'password': config.password,
										'data': {
											'title': randomTitle,
											'salt': salt,
											'keeBookChecksum': keeBookChecksum
										}
									}),
									'dataType': 'json',
									'contentType': 'application/json',
									'url': config.servicesUrl + '/' + config.username + '/createkeebook',
									'success': function(data) {
										ok(data, "returned data is an object");
										ok(data.authSuccess, "authentication was successful");
										ok(data.success, "overall result was successful");
										ok(data.keeBookId, "keeBookId is included in result");
										keeBookId = data.keeBookId;

										start();
										crud_item_f30();
									},
									'error': function() {
										ok(false, "service call returned with error");
										start();
									}
								});
							});
						}

						function crud_item_f30() {
							asyncTest("CRUD Item: Add two new items via one request", function() {
								$.ajax({
									'type': 'POST',
									'data': JSON.stringify({
										'password': config.password,
										'keeBook': keeBookId,
										'keeBookChecksum': keeBookChecksum,
										'items': [
											{
												'title': randomItemTitleA,
												'username': Crypto.AES.encrypt('test', randomPassword),
												'password': Crypto.AES.encrypt('test', randomPassword),
												'url': Crypto.AES.encrypt('test', randomPassword),
												'notes': Crypto.AES.encrypt('test', randomPassword)
											},
											{
												'title': randomItemTitleB,
												'username': Crypto.AES.encrypt('test', randomPassword),
												'password': Crypto.AES.encrypt('test', randomPassword),
												'url': Crypto.AES.encrypt('test', randomPassword),
												'notes': Crypto.AES.encrypt('test', randomPassword)
											}
										]
									}),
									'dataType': 'json',
									'contentType': 'application/json',
									'url': config.servicesUrl + '/' + config.username + '/setitem',
									'success': function(data) {
										ok(data, "returned data is an object");
										ok(data.authSuccess, "authentication was successful");
										ok(data.success, "overall result was successful");
										ok(data.count, "count is included in result");
										ok((data.count == 2), "both items were created successfully");
										ok(data.itemIds, "itemIds is included in result");
										ok(data.itemIds.length == 2, "itemIds is has length = 2");
										itemIdA = data.itemIds[0];
										itemIdB = data.itemIds[1];

										start();
										crud_item_f40();
									},
									'error': function() {
										ok(false, "service call returned with error");
										start();
									}
								});
							});
						}

						function crud_item_f40() {
							asyncTest("CRUD Item: Get list of items (without constraint)", function() {
								$.ajax({
									'type': 'GET',
									'data': {
										'password': config.password,
										'keeBook': keeBookId,
										'keeBookChecksum': keeBookChecksum
									},
									'dataType': 'json',
									'url': config.servicesUrl + '/' + config.username + '/getitem',
									'success': function(data) {
										ok(data, "returned data is an object");
										ok(data.authSuccess, "authentication was successful");
										ok(data.success, "overall result was successful");
										ok(data.count, "count is included in result");
										ok(data.count == 2, "count is = 2");
										ok(data.result, "result list is included in result");
										ok(data.result.length == 2, "result list has correct length");
										
										var foundItemA = false;
										var foundItemB = false;
										for (var i=0; i<data.count; i++) {
											if (data.result[i].id == itemIdA) foundItemA = true;
											if (data.result[i].id == itemIdB) foundItemB = true;
										}
										ok(foundItemA && foundItemB, "both item ids are included in result");
		
										foundItemA = false;
										foundItemB = false;
										for (var i=0; i<data.count; i++) {
											if (data.result[i].id == itemIdA && data.result[i].title == randomItemTitleA) foundItemA = true;
											if (data.result[i].id == itemIdB && data.result[i].title == randomItemTitleB) foundItemB = true;
										}
										ok(foundItemA && foundItemB, "both items have the name set");

										start();
										crud_item_f50();
									},
									'error': function() {
										ok(false, "service call returned with error");
										start();
									}
								});
							});
						}

						function crud_item_f50() {
							asyncTest("CRUD Item: Delete new items", function() {
								$.ajax({
									'type': 'POST',
									'data': JSON.stringify({
										'password': config.password,
										'keeBook': keeBookId,
										'keeBookChecksum': keeBookChecksum,
										'itemsIds': [itemIdA, itemIdB]
									}),
									'dataType': 'json',
									'contentType': 'application/json',
									'url': config.servicesUrl + '/' + config.username + '/deleteitem',
									'success': function(data) {
										ok(data, "returned data is an object");
										ok(data.authSuccess, "authentication was successful");
										ok(data.success, "overall result was successful");
										ok(data.count, "count is included in result");

										start();
										crud_item_f60();
									},
									'error': function() {
										ok(false, "service call returned with error");
										start();
									}
								});
							});
						}

						function crud_item_f60() {
							asyncTest("CRUD Item: Delete temporarily created kee book", function() {
								$.ajax({
									'type': 'GET',
									'data': {
										'password': (config.password),
										'keeBook': keeBookId,
										'keeBookChecksum': keeBookChecksum
									},
									'dataType': 'json',
									'url': config.servicesUrl + '/' + config.username + '/deletekeebook',
									'success': function(data) {
										ok(data, "returned data is an object");
										ok(data.authSuccess, "authentication was successful");
										ok(data.success, "overall result was successful");
										start();
									},
									'error': function() {
										ok(false, "service call returned with error");
										start();
									}
								});
							});
						}
					}

					/***********************************************/
					/*        CRUD GROUP                           */
					/***********************************************/
					function crud_group() {
						var salt = "";
						var keeBookId = "";
						var keeBookChecksum = "";
						var randomTitle = "Test Kee Book " + Math.abs(Math.random()*1000000);
						var randomGroupTitle = "Test Group " + Math.abs(Math.random()*1000000);
						var randomItemTitleA = "Test Item " + Math.abs(Math.random()*1000000);
						var randomItemTitleB = "Test Item " + Math.abs(Math.random()*1000000);
						var randomPassword = Math.abs(Math.random()*1000000) + "";
						var groupId = "";
						var itemIdA = "";
						var itemIdB = "";

						crud_group_f10();

						function crud_group_f10() {
							asyncTest("CRUD Group: Request salt", function() {
								$.ajax({
									'type': 'GET',
									'data': {'password': (config.password)},
									'dataType': 'json',
									'url': config.servicesUrl + '/' + config.username + '/getsalt',
									'success': function(data) {
										ok(data, "returned data is an object");
										ok(data.authSuccess, "authentication was successful");
										ok(data.success, "overall result was successful");
										ok(data.salt, "salt is included in result");
										salt = data.salt;
										keeBookChecksum = Crypto.SHA256(Crypto.SHA256(randomPassword) + salt);
										
										start();
										crud_group_f20();
									},
									'error': function() {
										ok(false, "service call returned with error");
										start();
									}
								});
							});
						}
						
						function crud_group_f20() {
							asyncTest("CRUD Group: Create blank kee book", function() {
								$.ajax({
									'type': 'POST',
									'data': JSON.stringify({
										'password': config.password,
										'data': {
											'title': randomTitle,
											'salt': salt,
											'keeBookChecksum': keeBookChecksum
										}
									}),
									'dataType': 'json',
									'contentType': 'application/json',
									'url': config.servicesUrl + '/' + config.username + '/createkeebook',
									'success': function(data) {
										ok(data, "returned data is an object");
										ok(data.authSuccess, "authentication was successful");
										ok(data.success, "overall result was successful");
										ok(data.keeBookId, "keeBookId is included in result");
										keeBookId = data.keeBookId;

										start();
										crud_group_f30();
									},
									'error': function() {
										ok(false, "service call returned with error");
										start();
									}
								});
							});
						}

						function crud_group_f30() {
							asyncTest("CRUD Group: Create a new group", function() {
								$.ajax({
									'type': 'POST',
									'data': JSON.stringify({
										'password': config.password,
										'keeBook': keeBookId,
										'keeBookChecksum': keeBookChecksum,
										'data': {
											'title': randomGroupTitle
										}
									}),
									'dataType': 'json',
									'contentType': 'application/json',
									'url': config.servicesUrl + '/' + config.username + '/setgroup',
									'success': function(data) {
										ok(data, "returned data is an object");
										ok(data.authSuccess, "authentication was successful");
										ok(data.success, "overall result was successful");
										ok(data.groupId, "groupId is included in result");
										groupId = data.groupId;

										start();
										crud_group_f40();
									},
									'error': function() {
										ok(false, "service call returned with error");
										start();
									}
								});
							});
						}

						function crud_group_f40() {
							asyncTest("CRUD Group: Get list of groups", function() {
								$.ajax({
									'type': 'GET',
									'data': {
										'password': (config.password),
										'keeBook': keeBookId,
										'keeBookChecksum': keeBookChecksum
									},
									'dataType': 'json',
									'url': config.servicesUrl + '/' + config.username + '/getgroup',
									'success': function(data) {
										ok(data, "returned data is an object");
										ok(data.authSuccess, "authentication was successful");
										ok(data.success, "overall result was successful");
										ok(data.count, "count is included");
										ok(data.result, "result object is included");
										var included = false;
										for (var i=0; i<data.count; i++) {
											if (data.result[i].id == groupId && data.result[i].title == randomGroupTitle) included = true;
										}
										ok(included, "group is included in list");
											
										start();
										crud_group_f50();
									},
									'error': function() {
										ok(false, "service call returned with error");
										start();
									}
								});
							});
						}

						function crud_group_f50() {
							asyncTest("CRUD Group: Add two new items via one request, one with group, one without", function() {
								$.ajax({
									'type': 'POST',
									'data': JSON.stringify({
										'password': config.password,
										'keeBook': keeBookId,
										'keeBookChecksum': keeBookChecksum,
										'items': [
											{
												'title': randomItemTitleA,
												'username': Crypto.AES.encrypt('test', randomPassword),
												'password': Crypto.AES.encrypt('test', randomPassword),
												'url': Crypto.AES.encrypt('test', randomPassword),
												'notes': Crypto.AES.encrypt('test', randomPassword),
												'group': groupId
											},
											{
												'title': randomItemTitleB,
												'username': Crypto.AES.encrypt('test', randomPassword),
												'password': Crypto.AES.encrypt('test', randomPassword),
												'url': Crypto.AES.encrypt('test', randomPassword),
												'notes': Crypto.AES.encrypt('test', randomPassword)
											}
										]
									}),
									'dataType': 'json',
									'contentType': 'application/json',
									'url': config.servicesUrl + '/' + config.username + '/setitem',
									'success': function(data) {
										ok(data, "returned data is an object");
										ok(data.authSuccess, "authentication was successful");
										ok(data.success, "overall result was successful");
										ok(data.count, "count is included in result");
										ok((data.count == 2), "both items were created successfully");
										ok(data.itemIds, "itemIds is included in result");
										ok(data.itemIds.length == 2, "itemIds is has length = 2");
										itemIdA = data.itemIds[0];
										itemIdB = data.itemIds[1];

										start();
										crud_group_f62();
									},
									'error': function() {
										ok(false, "service call returned with error");
										start();
									}
								});
							});
						}

						function crud_group_f62() {
							asyncTest("CRUD Group: Get list of items and check groups (without constraints)", function() {
								$.ajax({
									'type': 'GET',
									'data': {
										'password': config.password,
										'keeBook': keeBookId,
										'keeBookChecksum': keeBookChecksum
									},
									'dataType': 'json',
									'url': config.servicesUrl + '/' + config.username + '/getitem',
									'success': function(data) {
										ok(data, "returned data is an object");
										ok(data.authSuccess, "authentication was successful");
										ok(data.success, "overall result was successful");
										ok(data.count, "count is included in result");
										ok(data.count == 2, "count is = 2");
										ok(data.result, "result list is included in result");
										ok(data.result.length == 2, "result list has correct length");
										
										var foundItemA = false;
										var foundItemB = false;
										for (var i=0; i<data.count; i++) {
											if (data.result[i].id == itemIdA) foundItemA = true;
											if (data.result[i].id == itemIdB) foundItemB = true;
										}
										ok(foundItemA && foundItemB, "both item ids are included in result");
		
										foundItemA = false;
										foundItemB = false;
										for (var i=0; i<data.count; i++) {
											if (data.result[i].id == itemIdA && data.result[i].group == groupId) foundItemA = true;
											if (data.result[i].id == itemIdB && !data.result[i].group) foundItemB = true;
										}
										ok(foundItemA && foundItemB, "both items have the correct group associated");

										start();
										crud_group_f64();
									},
									'error': function() {
										ok(false, "service call returned with error");
										start();
									}
								});
							});
						}

						function crud_group_f64() {
							asyncTest("CRUD Group: Get list of items and check groups (with group constraint)", function() {
								$.ajax({
									'type': 'GET',
									'data': {
										'password': config.password,
										'keeBook': keeBookId,
										'keeBookChecksum': keeBookChecksum,
										'group': groupId
									},
									'dataType': 'json',
									'url': config.servicesUrl + '/' + config.username + '/getitem',
									'success': function(data) {
										ok(data, "returned data is an object");
										ok(data.authSuccess, "authentication was successful");
										ok(data.success, "overall result was successful");
										ok(data.count, "count is included in result");
										ok(data.count == 1, "count is = 1");
										ok(data.result, "result list is included in result");
										ok(data.result.length == 1, "result list has correct length");
										
										var foundItemA = false;
										for (var i=0; i<data.count; i++) {
											if (data.result[i].id == itemIdA) foundItemA = true;
										}
										ok(foundItemA, "expected item is included in result");
		
										foundItemA = false;
										for (var i=0; i<data.count; i++) {
											if (data.result[i].id == itemIdA && data.result[i].group == groupId) foundItemA = true;
										}
										ok(foundItemA, "item has the correct group associated");

										start();
										crud_group_f60();
									},
									'error': function() {
										ok(false, "service call returned with error");
										start();
									}
								});
							});
						}

						function crud_group_f60() {
							asyncTest("CRUD Group: Delete group", function() {
								$.ajax({
									'type': 'GET',
									'data': {
										'password': (config.password),
										'keeBook': keeBookId,
										'keeBookChecksum': keeBookChecksum,
										'id': groupId
									},
									'dataType': 'json',
									'url': config.servicesUrl + '/' + config.username + '/deletegroup',
									'success': function(data) {
										ok(data, "returned data is an object");
										ok(data.authSuccess, "authentication was successful");
										ok(data.success, "overall result was successful");

										start();
										crud_group_f65();
									},
									'error': function() {
										ok(false, "service call returned with error");
										start();
									}
								});
							});
						}

						function crud_group_f65() {
							asyncTest("CRUD Group: Get list of items and check groups (without constraints)", function() {
								$.ajax({
									'type': 'GET',
									'data': {
										'password': config.password,
										'keeBook': keeBookId,
										'keeBookChecksum': keeBookChecksum
									},
									'dataType': 'json',
									'url': config.servicesUrl + '/' + config.username + '/getitem',
									'success': function(data) {
										ok(data, "returned data is an object");
										ok(data.authSuccess, "authentication was successful");
										ok(data.success, "overall result was successful");
										ok(data.count, "count is included in result");
										ok(data.count == 1, "count is = 1");
										ok(data.result, "result list is included in result");
										ok(data.result.length == 1, "result list has correct length");
										
										var foundItemB = false;
										for (var i=0; i<data.count; i++) {
											if (data.result[i].id == itemIdB) foundItemB = true;
										}
										ok(foundItemB, "item id is included in result");
		
										foundItemB = false;
										for (var i=0; i<data.count; i++) {
											if (data.result[i].id == itemIdB && !data.result[i].group) foundItemB = true;
										}
										ok(foundItemB, "item has the correct group associated");

										start();
										crud_group_f70();
									},
									'error': function() {
										ok(false, "service call returned with error");
										start();
									}
								});
							});
						}

						function crud_group_f70() {
							asyncTest("CRUD Group: Delete kee book", function() {
								$.ajax({
									'type': 'GET',
									'data': {
										'password': (config.password),
										'keeBook': keeBookId,
										'keeBookChecksum': keeBookChecksum
									},
									'dataType': 'json',
									'url': config.servicesUrl + '/' + config.username + '/deletekeebook',
									'success': function(data) {
										ok(data, "returned data is an object");
										ok(data.authSuccess, "authentication was successful");
										ok(data.success, "overall result was successful");

										start();
									},
									'error': function() {
										ok(false, "service call returned with error");
										start();
									}
								});
							});
						}
					}
				});
			/* ]]> */
		</script>
	</head>
	<body>
		<h1 id="qunit-header">QUnit: Kee Book RS Web Services</h1>
		<h2 id="qunit-banner"></h2>
		<div id="qunit-testrunner-toolbar"></div>
		<h2 id="qunit-userAgent"></h2>
		<ol id="qunit-tests"></ol>
		<div id="qunit-fixture"></div>
	</body>
</html>